package com.blog.cloud.security.service.impl;

import com.blog.cloud.api.dto.UserInfoDto;
import com.blog.cloud.api.entity.User;
import com.blog.cloud.api.feign.UserFeignService;
import com.blog.cloud.api.vo.auth.UserInfoVO;
import com.blog.cloud.cache.constants.CacheConstant;
import com.blog.cloud.core.exception.BlogException;
import com.blog.cloud.core.utils.BeanCopyUtil;
import com.blog.cloud.core.utils.R;
import com.blog.cloud.security.bo.UserInfo;
import com.blog.cloud.security.service.UserDetailService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service("userDetailService")
public class UserDetailServiceImpl implements UserDetailService {

    private final UserFeignService userFeignService;

    private final CacheManager cacheManager;

    /**
     * 登录认证,只需要获取用户信息，密码匹配在之后的源码流程会进行匹配检查
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 先从redis缓存中查认证信息，如果不为空则
        Cache cache = cacheManager.getCache(CacheConstant.USER_DETAIL);
        if (cache != null && cache.get(username) != null) {
            return (UserInfo) Objects.requireNonNull(cache.get(username)).get();
        }

        R<UserInfoDto> result = userFeignService.findUserByUsername(username);
        UserInfo userDetails = getUserDetails(result);

        if (Objects.nonNull(cache)) {
            cache.put(username, userDetails);
        }
        return userDetails;
    }

    /**
     * 封装用户详细信息时，将用户角色带上，用于登陆时根据用户角色设置不同角色的账号过期时间
     */
    private UserInfo getUserDetails(R<UserInfoDto> result) {
        UserInfoDto userInfoDto = Optional.of(result.getData()).get();
        User user = userInfoDto.getUser();
        // 用户基本信息，登陆成功返回给前端
        UserInfoVO userInfoVO = BeanCopyUtil.singleCopy(user, UserInfoVO.class);
        Set<SimpleGrantedAuthority> authorities = userInfoDto.getRoles().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
        return new UserInfo(user.getUsername(), user.getPassword(), userInfoVO, userInfoDto.getRoles(), authorities);
    }

    @Override
    public UserDetails loadUserByMobile(String mobile) throws BlogException {
        Cache cache = cacheManager.getCache(CacheConstant.USER_DETAIL);
        if (cache != null && cache.get(mobile) != null) {
            UserInfoDto userInfoDto = (UserInfoDto) Objects.requireNonNull(cache.get(mobile)).get();
            return getUserDetails(R.ok(userInfoDto));
        }

        R<UserInfoDto> result = userFeignService.findUserByMobile(mobile);
        UserInfo userDetails = getUserDetails(result);

        if (Objects.nonNull(cache)) {
            cache.put(mobile, userDetails);
        }
        return userDetails;
    }
}
